home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / Src / Ch3 / CopyDIB.bas < prev    next >
BASIC Source File  |  1999-03-24  |  19KB  |  571 lines

  1. Attribute VB_Name = "DIBHelper"
  2. Option Explicit
  3.  
  4. ' ------------------------
  5. ' Bitmap Array Information
  6. ' ------------------------
  7. Public Type RGBTriplet
  8.     rgbRed As Byte
  9.     rgbGreen As Byte
  10.     rgbBlue As Byte
  11. End Type
  12.  
  13. ' ------------------
  14. ' Bitmap Information
  15. ' ------------------
  16. Public Type RGBQUAD
  17.     rgbBlue As Byte
  18.     rgbGreen As Byte
  19.     rgbRed As Byte
  20.     rgbReserved As Byte
  21. End Type
  22. Public Type BITMAPINFOHEADER
  23.     biSize As Long
  24.     biWidth As Long
  25.     biHeight As Long
  26.     biPlanes As Integer
  27.     biBitCount As Integer
  28.     biCompression As Long
  29.     biSizeImage As Long
  30.     biXPelsPerMeter As Long
  31.     biYPelsPerMeter As Long
  32.     biClrUsed As Long
  33.     biClrImportant As Long
  34. End Type
  35.  
  36. ' BITMAPINFO structure with room for up to
  37. ' 256 colors.
  38. Public Type BITMAPINFO
  39.     bmiHeader As BITMAPINFOHEADER
  40.     bmiColors(0 To 255) As RGBQUAD
  41. End Type
  42.  
  43. ' Error codes.
  44. Public Enum dibhErrors
  45.     dibhInvalidBitsPerPixel = vbObjectError + 1001
  46.     dibhCreateDCFailed
  47.     dibhCreateBitmapFailed
  48.     dibhSelectPaletteFailed
  49.     dibhBitBltFailed
  50.     dibhDeselectBitmapFailed
  51.     dibhGetDIBitsFailed
  52.     dibhStretchDIBitsFailed
  53. End Enum
  54.  
  55. ' API functions.
  56. Private Declare Function SelectPalette Lib "gdi32" (ByVal hdc As Long, ByVal hPalette As Long, ByVal bForceBackground As Long) As Long
  57. Private Declare Function RealizePalette Lib "gdi32" (ByVal hdc As Long) As Long
  58. Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
  59. Private Declare Function CreateCompatibleBitmap Lib "gdi32" (ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
  60. Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
  61. Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
  62. Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
  63. Private Declare Function GetDIBits Lib "gdi32" (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpBI As BITMAPINFO, ByVal wUsage As Long) As Long
  64. Private Declare Function StretchDIBits Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long, ByVal dx As Long, ByVal dy As Long, ByVal SrcX As Long, ByVal SrcY As Long, ByVal wSrcWidth As Long, ByVal wSrcHeight As Long, lpBits As Any, lpBitsInfo As BITMAPINFO, ByVal wUsage As Long, ByVal dwRop As Long) As Long
  65.  
  66. ' API constants.
  67. Private Const SRCCOPY = &HCC0020
  68. Private Const BI_RGB = 0&
  69. Private Const DIB_RGB_COLORS = 0
  70. Private Const GDI_ERROR = &HFFFF
  71.  
  72. ' Return a binary representation of the byte.
  73. ' This helper function is useful for understanding
  74. ' byte values.
  75. Public Function BinaryByte(ByVal value As Byte) As String
  76. Dim i As Integer
  77. Dim txt As String
  78.  
  79.     For i = 1 To 8
  80.         If value And 1 Then
  81.             txt = "1" & txt
  82.         Else
  83.             txt = "0" & txt
  84.         End If
  85.         value = value \ 2
  86.     Next i
  87.  
  88.     BinaryByte = txt
  89. End Function
  90.  
  91. ' Find the closest color in the Colors array.
  92. Public Function FindColorIndex(ByVal r As Integer, ByVal g As Integer, ByVal b As Integer, ByVal num_colors As Integer, Colors() As RGBQUAD) As Byte
  93. Dim i As Integer
  94. Dim best_i As Integer
  95. Dim best_dist2 As Long
  96. Dim dr As Long
  97. Dim dg As Long
  98. Dim db As Long
  99. Dim dist2 As Long
  100.  
  101.     best_i = 0
  102.     best_dist2 = CLng(3) * 256 * 256
  103.     For i = 0 To num_colors - 1
  104.         With Colors(i)
  105.             dr = r - .rgbRed
  106.             dg = g - .rgbGreen
  107.             db = b - .rgbBlue
  108.         End With
  109.         dist2 = dr * dr + dg * dg + db * db
  110.         If best_dist2 > dist2 Then
  111.             best_dist2 = dist2
  112.             best_i = i
  113.         End If
  114.     Next i
  115.  
  116.     FindColorIndex = best_i
  117. End Function
  118.  
  119. ' Load the bits from this PictureBox with a color
  120. ' depth of 24 bits into a two-dimensional array of
  121. ' RGB values.
  122. '
  123. ' Note that the pixels are flipped vertically in
  124. ' the DIB structure. This routine flips them
  125. ' so the upper left corner is at pixels(0, 0).
  126. Public Sub GetDIBPixels24Bit(ByVal pic As PictureBox, ByRef bitmap_info As BITMAPINFO, ByRef pixels() As RGBTriplet)
  127. Dim memory_dc As Long
  128. Dim new_bmp As Long
  129. Dim old_bmp As Long
  130. Dim wid As Long
  131. Dim hgt As Long
  132. Dim old_hpal As Long
  133. Dim bytes_per_row As Long
  134. Dim bytes() As Byte
  135. Dim X As Integer
  136. Dim Y As Integer
  137. Dim bits_per_pixel As Long
  138.  
  139.     bits_per_pixel = 24
  140.  
  141.     ' Get the image's dimensions.
  142.     wid = pic.ScaleX(pic.Image.Width, vbHimetric, vbPixels)
  143.     hgt = pic.ScaleY(pic.Image.Height, vbHimetric, vbPixels)
  144.  
  145.     ' Create a memory device context (DC).
  146.     memory_dc = CreateCompatibleDC(pic.hdc)
  147.     If memory_dc = 0 Then
  148.         Err.Raise dibhCreateDCFailed, _
  149.             "DIBHelper.GetDIBPixels24Bit", _
  150.             "Error creating compatible device context"
  151.     End If
  152.  
  153.     ' Create a compatible bitmap.
  154.     new_bmp = CreateCompatibleBitmap(pic.hdc, wid, hgt)
  155.     If new_bmp = 0 Then
  156.         Err.Raise dibhCreateBitmapFailed, _
  157.             "DIBHelper.GetDIBPixels24Bit", _
  158.             "Error creating compatible bitmap"
  159.     End If
  160.  
  161.     ' Select the bitmap into the DC, saving
  162.     ' its old bitmap handle.
  163.     old_bmp = SelectObject(memory_dc, new_bmp)
  164.  
  165.     ' Make sure the PictureBox has an Image.
  166.     pic.AutoRedraw = True
  167.  
  168.     ' If the picture has a palette,
  169.     ' get and realize a copy.
  170.     If pic.Image.hPal <> 0 Then
  171.         ' Select the palette.
  172.         old_hpal = SelectPalette(memory_dc, pic.Image.hPal, False)
  173.         If old_hpal = 0 Then
  174.             Err.Raise dibhSelectPaletteFailed, _
  175.                 "DIBHelper.GetDIBPixels24Bit", _
  176.                 "Error selecting palette into compatible bitmap"
  177.         End If
  178.         
  179.         ' Realize the palette.
  180.         RealizePalette memory_dc
  181.     End If
  182.  
  183.     ' Copy the image from the PictureBox
  184.     ' into the DC in memory.
  185.     If BitBlt(memory_dc, 0, 0, wid, hgt, _
  186.         pic.hdc, 0, 0, SRCCOPY) = 0 _
  187.     Then
  188.         Err.Raise dibhBitBltFailed, _
  189.             "DIBHelper.GetDIBPixels24Bit", _
  190.             "Error copying image from PictureBox into compatible bitmap"
  191.     End If
  192.  
  193.     ' Deselect the compatible bitmap. GetDIBits
  194.     ' requires that the bitmap from which it loads
  195.     ' data is not selected by any DC.
  196.     new_bmp = SelectObject(memory_dc, old_bmp)
  197.     If new_bmp = 0 Then
  198.         Err.Raise dibhDeselectBitmapFailed, _
  199.             "DIBHelper.GetDIBPixels24Bit", _
  200.             "Error deselecting the compatible bitmap"
  201.     End If
  202.  
  203.     ' Initialize important bitmap info header fields.
  204.     With bitmap_info.bmiHeader
  205.         .biSize = Len(bitmap_info.bmiHeader)
  206.         .biWidth = wid
  207.         .biHeight = hgt
  208.         .biPlanes = 1
  209.         .biBitCount = bits_per_pixel
  210.         .biCompression = BI_RGB
  211.     End With
  212.  
  213.     ' Calculate the number of bytes per row needed
  214.     ' to store the bitmap data. This is rounded up
  215.     ' to the next multiple of 32 pixels (4 bytes).
  216.     bytes_per_row = _
  217.         ((wid * bits_per_pixel + 31) \ 32) * 4
  218.  
  219.     ' Allocate the array for the pixel data.
  220.     ReDim bytes(0 To bytes_per_row - 1, 0 To hgt - 1)
  221.  
  222.     ' Get the bitmap data.
  223.     If GetDIBits(memory_dc, new_bmp, 0, hgt, _
  224.         bytes(0, 0), bitmap_info, DIB_RGB_COLORS) = 0 _
  225.     Then
  226.         Err.Raise dibhGetDIBitsFailed, _
  227.             "DIBHelper.GetDIBPixels24Bit", _
  228.             "Error using GetDIBits"
  229.     End If
  230.  
  231.     ' Delete the objects we created.
  232.     DeleteObject new_bmp
  233.     DeleteObject memory_dc
  234.  
  235.     ' Create the pixels array.
  236.     ReDim pixels(0 To wid - 1, 0 To hgt - 1)
  237.  
  238.     ' Copy the color values into the pixels array.
  239.     For Y = 0 To hgt - 1
  240.         For X = 0 To wid - 1
  241.             With pixels(X, hgt - 1 - Y)
  242.                 .rgbBlue = bytes(X * 3, Y)
  243.                 .rgbGreen = bytes(X * 3 + 1, Y)
  244.                 .rgbRed = bytes(X * 3 + 2, Y)
  245.             End With
  246.         Next X
  247.     Next Y
  248. End Sub
  249. ' Load the bits from this PictureBox with a color
  250. ' depth of 1, 4, or 8 bits into a two-dimensional
  251. ' array of color index values.
  252. '
  253. ' Note that the pixels are flipped vertically in
  254. ' the DIB structure. This routine flips them
  255. ' so the upper left corner is at pixels(0, 0).
  256. Public Sub GetDIBPixelsWithPalette(ByVal pic As PictureBox, ByRef bitmap_info As BITMAPINFO, color_index() As Byte, ByVal bits_per_pixel As Long)
  257. Dim memory_dc As Long
  258. Dim new_bmp As Long
  259. Dim old_bmp As Long
  260. Dim wid As Long
  261. Dim hgt As Long
  262. Dim old_hpal As Long
  263. Dim bytes_per_row As Long
  264. Dim bytes() As Byte
  265. Dim X As Integer
  266. Dim Y As Integer
  267. Dim shift_value As Integer
  268. Dim i As Integer
  269.  
  270.     ' Verify that bits_per_pixel is 1, 4, or 8.
  271.     If (bits_per_pixel <> 1) And _
  272.        (bits_per_pixel <> 4) And _
  273.        (bits_per_pixel <> 8) _
  274.     Then
  275.         Err.Raise dibhInvalidBitsPerPixel, _
  276.             "DIBHelper.GetDIBPixelsWithPalette", _
  277.             "The number of bits per pixel must be 1, 4, or 8"
  278.     End If
  279.  
  280.     ' Get the image's dimensions.
  281.     wid = pic.ScaleX(pic.Image.Width, vbHimetric, vbPixels)
  282.     hgt = pic.ScaleY(pic.Image.Height, vbHimetric, vbPixels)
  283.  
  284.     ' Create a memory device context (DC).
  285.     memory_dc = CreateCompatibleDC(pic.hdc)
  286.     If memory_dc = 0 Then
  287.         Err.Raise dibhCreateDCFailed, _
  288.             "DIBHelper.GetDIBPixelsWithPalette", _
  289.             "Error creating compatible device context"
  290.     End If
  291.  
  292.     ' Create a compatible bitmap.
  293.     new_bmp = CreateCompatibleBitmap(pic.hdc, wid, hgt)
  294.     If new_bmp = 0 Then
  295.         Err.Raise dibhCreateBitmapFailed, _
  296.             "DIBHelper.GetDIBPixelsWithPalette", _
  297.             "Error creating compatible bitmap"
  298.     End If
  299.  
  300.     ' Select the bitmap into the DC, saving
  301.     ' its old bitmap handle.
  302.     old_bmp = SelectObject(memory_dc, new_bmp)
  303.  
  304.     ' Make sure the PictureBox has an Image.
  305.     pic.AutoRedraw = True
  306.  
  307.     ' If the picture has a palette,
  308.     ' get and realize a copy.
  309.     If pic.Image.hPal <> 0 Then
  310.         ' Select the palette.
  311.         old_hpal = SelectPalette(memory_dc, pic.Image.hPal, False)
  312.         If old_hpal = 0 Then
  313.             Err.Raise dibhSelectPaletteFailed, _
  314.                 "DIBHelper.GetDIBPixelsWithPalette", _
  315.                 "Error selecting palette into compatible bitmap"
  316.         End If
  317.         
  318.         ' Realize the palette.
  319.         RealizePalette memory_dc
  320.     End If
  321.  
  322.     ' Copy the image from the PictureBox
  323.     ' into the DC in memory.
  324.     If BitBlt(memory_dc, 0, 0, wid, hgt, _
  325.         pic.hdc, 0, 0, SRCCOPY) = 0 _
  326.     Then
  327.         Err.Raise dibhBitBltFailed, _
  328.             "DIBHelper.GetDIBPixelsWithPalette", _
  329.             "Error copying image from PictureBox into compatible bitmap"
  330.     End If
  331.  
  332.     ' Deselect the compatible bitmap. GetDIBits
  333.     ' requires that the bitmap from which it loads
  334.     ' data is not selected by any DC.
  335.     new_bmp = SelectObject(memory_dc, old_bmp)
  336.     If new_bmp = 0 Then
  337.         Err.Raise dibhDeselectBitmapFailed, _
  338.             "DIBHelper.GetDIBPixelsWithPalette", _
  339.             "Error deselecting the compatible bitmap"
  340.     End If
  341.  
  342.     ' Initialize important bitmap info header fields.
  343.     With bitmap_info.bmiHeader
  344.         .biSize = Len(bitmap_info.bmiHeader)
  345.         .biWidth = wid
  346.         .biHeight = hgt
  347.         .biPlanes = 1
  348.         .biBitCount = bits_per_pixel
  349.         .biCompression = BI_RGB
  350.     End With
  351.  
  352.     ' Calculate the number of bytes per row needed
  353.     ' to store the bitmap data. This is rounded up
  354.     ' to the next multiple of 32 pixels (4 bytes).
  355.     bytes_per_row = _
  356.         ((wid * bits_per_pixel + 31) \ 32) * 4
  357.  
  358.     ' Allocate the array for bitmap data.
  359.     ReDim bytes(0 To bytes_per_row - 1, 0 To hgt - 1)
  360.  
  361.     ' Get the bitmap data.
  362.     If GetDIBits(memory_dc, new_bmp, 0, hgt, _
  363.         bytes(0, 0), bitmap_info, DIB_RGB_COLORS) = 0 _
  364.     Then
  365.         Err.Raise dibhGetDIBitsFailed, _
  366.             "DIBHelper.GetDIBPixelsWithPalette", _
  367.             "Error using GetDIBits"
  368.     End If
  369.  
  370.     ' Delete the objects we created.
  371.     DeleteObject new_bmp
  372.     DeleteObject memory_dc
  373.  
  374.     ' Fill the color_index array.
  375.     Select Case bits_per_pixel
  376.         Case 1
  377.             ' Allow room for all of the bytes array
  378.             ' entries, even though some of those
  379.             ' were added to make each row contain
  380.             ' a multiple of 4 bytes.
  381.             ReDim color_index(0 To (8 * bytes_per_row) - 1, 0 To hgt - 1)
  382.  
  383.             ' Copy the color index data.
  384.             For Y = 0 To hgt - 1
  385.                 For X = 0 To bytes_per_row - 1
  386.                     shift_value = 128
  387.                     For i = 0 To 7
  388.                         If bytes(X, Y) And shift_value Then
  389.                             color_index(8 * X + i, hgt - 1 - Y) = 1
  390.                         Else
  391.                             color_index(8 * X + i, hgt - 1 - Y) = 0
  392.                         End If
  393.                         shift_value = shift_value \ 2
  394.                     Next i
  395.                 Next X
  396.             Next Y
  397.  
  398.         Case 4
  399.             ' Allow room for all of the bytes array
  400.             ' entries, even though some of those
  401.             ' were added to make each row contain
  402.             ' a multiple of 4 bytes.
  403.             ReDim color_index(0 To (2 * bytes_per_row) - 1, 0 To hgt - 1)
  404.  
  405.             ' Copy the color index data.
  406.             ' new_x gives the first index of the
  407.             ' next entry in color_index.
  408.             For Y = 0 To hgt - 1
  409.                 For X = 0 To bytes_per_row - 1
  410.                     color_index(2 * X, hgt - 1 - Y) = _
  411.                         bytes(X, Y) \ 16
  412.                     color_index(2 * X + 1, hgt - 1 - Y) = _
  413.                         bytes(X, Y) Mod 16
  414.                 Next X
  415.             Next Y
  416.  
  417.         Case 8
  418.             ' Allocate the color index array.
  419.             ReDim color_index(0 To wid - 1, 0 To hgt - 1)
  420.  
  421.             ' Fill the color_index array.
  422.             For Y = 0 To hgt - 1
  423.                 For X = 0 To wid - 1
  424.                     color_index(X, hgt - 1 - Y) = bytes(X, Y)
  425.                 Next X
  426.             Next Y
  427.  
  428.     End Select
  429. End Sub
  430.  
  431. ' Set the bits in this PictureBox using a
  432. ' two-dimensional array of RGB values.
  433. '
  434. ' Note that the pixels are flipped vertically in
  435. ' the DIB structure. This routine flips them back
  436. ' so the upper left corner is at pixels(0, 0).
  437. Public Sub SetDIBPixels24Bit(ByVal pic As PictureBox, bitmap_info As BITMAPINFO, pixels() As RGBTriplet)
  438. Dim wid As Integer
  439. Dim hgt As Integer
  440. Dim bytes_per_row As Integer
  441. Dim bits_per_pixel As Integer
  442. Dim bytes() As Byte
  443. Dim clr As Byte
  444. Dim X As Integer
  445. Dim Y As Integer
  446.  
  447.     ' See how big the image is.
  448.     wid = bitmap_info.bmiHeader.biWidth
  449.     hgt = bitmap_info.bmiHeader.biHeight
  450.     bits_per_pixel = bitmap_info.bmiHeader.biBitCount
  451.  
  452.     ' Calculate the number of bytes per row needed
  453.     ' to store the bitmap data. This is rounded up
  454.     ' to the next multiple of 32 pixels (4 bytes).
  455.     bytes_per_row = _
  456.         ((wid * bits_per_pixel + 31) \ 32) * 4
  457.  
  458.     ' Allocate the bytes array.
  459.     ReDim bytes(0 To bytes_per_row - 1, 0 To hgt - 1)
  460.  
  461.     ' Copy the pixel information into the bytes array.
  462.     For Y = 0 To hgt - 1
  463.         For X = 0 To wid - 1
  464.             With pixels(X, hgt - 1 - Y)
  465.                 bytes(X * 3, Y) = .rgbBlue
  466.                 bytes(X * 3 + 1, Y) = .rgbGreen
  467.                 bytes(X * 3 + 2, Y) = .rgbRed
  468.             End With
  469.         Next X
  470.     Next Y
  471.  
  472.     ' Copy the DIB information into the picture.
  473.     If StretchDIBits( _
  474.         pic.hdc, 0, 0, wid, hgt, _
  475.         0, 0, wid, hgt, bytes(0, 0), bitmap_info, _
  476.         DIB_RGB_COLORS, SRCCOPY) = GDI_ERROR _
  477.     Then
  478.         Err.Raise dibhStretchDIBitsFailed, _
  479.             "DIBHelper.SetDIBPixels24Bit", _
  480.             "Error using StretchDIBits"
  481.     End If
  482.  
  483.     ' Make the changes visible.
  484.     pic.Picture = pic.Image
  485. End Sub
  486. ' Set the bits in this PictureBox using a 0-based
  487. ' two-dimensional array of color indexes.
  488. '
  489. ' Note that the pixels are flipped vertically in
  490. ' the DIB structure. This routine flips them back
  491. ' so the upper left corner is at pixels(0, 0).
  492. Public Sub SetDIBPixelsWithPalette(ByVal pic As PictureBox, bitmap_info As BITMAPINFO, color_index() As Byte)
  493. Dim wid As Integer
  494. Dim hgt As Integer
  495. Dim bytes_per_row As Integer
  496. Dim bits_per_pixel As Integer
  497. Dim bytes() As Byte
  498. Dim clr As Byte
  499. Dim X As Integer
  500. Dim Y As Integer
  501. Dim shift_value As Integer
  502. Dim i As Integer
  503. Dim byte_value As Integer
  504.  
  505.     ' See how big the image is.
  506.     wid = bitmap_info.bmiHeader.biWidth
  507.     hgt = bitmap_info.bmiHeader.biHeight
  508.     bits_per_pixel = bitmap_info.bmiHeader.biBitCount
  509.  
  510.     ' Calculate the number of bytes per row needed
  511.     ' to store the bitmap data. This is rounded up
  512.     ' to the next multiple of 32 pixels (4 bytes).
  513.     bytes_per_row = _
  514.         ((wid * bits_per_pixel + 31) \ 32) * 4
  515.  
  516.     ' Allocate the bytes array.
  517.     ReDim bytes(0 To bytes_per_row - 1, 0 To hgt - 1)
  518.  
  519.     ' Copy the pixel information into the bytes array.
  520.     Select Case bits_per_pixel
  521.         Case 1
  522.             ' Define the color data.
  523.             For Y = 0 To hgt - 1
  524.                 For X = 0 To bytes_per_row - 1
  525.                     shift_value = 128
  526.                     byte_value = 0
  527.                     For i = 0 To 7
  528.                         If color_index(8 * X + i, hgt - 1 - Y) = 1 Then
  529.                             byte_value = byte_value Or shift_value
  530.                         End If
  531.                         shift_value = shift_value \ 2
  532.                     Next i
  533.                     bytes(X, Y) = byte_value And &HFF&
  534.                 Next X
  535.             Next Y
  536.  
  537.         Case 4
  538.             ' Define the color data.
  539.             For Y = 0 To hgt - 1
  540.                 For X = 0 To bytes_per_row - 1
  541.                     bytes(X, Y) = _
  542.                         16 * color_index(2 * X, hgt - 1 - Y) + _
  543.                         color_index(2 * X + 1, hgt - 1 - Y)
  544.                 Next X
  545.             Next Y
  546.  
  547.         Case 8
  548.             ' Define the color data.
  549.             For Y = 0 To hgt - 1
  550.                 For X = 0 To wid - 1
  551.                     bytes(X, hgt - 1 - Y) = color_index(X, Y)
  552.                 Next X
  553.             Next Y
  554.  
  555.     End Select
  556.  
  557.     ' Copy the DIB information into the picture.
  558.     If StretchDIBits( _
  559.         pic.hdc, 0, 0, wid, hgt, _
  560.         0, 0, wid, hgt, bytes(0, 0), bitmap_info, _
  561.         DIB_RGB_COLORS, SRCCOPY) = GDI_ERROR _
  562.     Then
  563.         Err.Raise dibhStretchDIBitsFailed, _
  564.             "DIBHelper.SetDIBPixels24Bit", _
  565.             "Error using StretchDIBits"
  566.     End If
  567.  
  568.     ' Make the changes visible.
  569.     pic.Picture = pic.Image
  570. End Sub
  571.